package com.tian.service.impl;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.tian.common.CommonResult;
import com.tian.dto.*;
import com.tian.dto.exchange.ExchangeCodeDto;
import com.tian.entity.ChargeActivity;
import com.tian.entity.ChargeActivityCondition;
import com.tian.entity.ChargeCoupon;
import com.tian.entity.ExchangeCode;
import com.tian.enums.*;
import com.tian.exception.BusinessException;
import com.tian.mapper.ChargeCouponMapper;
import com.tian.mapper.ExchangeCodeMapper;
import com.tian.service.ChargeCouponService;
import com.tian.util.ChargeMarketRedisKeyPrefix;
import com.tian.util.CodeUtil;
import com.tian.util.CouponCodeUtil;
import com.tian.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBucket;
import org.redisson.api.RList;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * {@code @description:} 优惠券实现类
 *
 * @author tianwc 公众号：Java后端技术全栈
 * 在线刷题 1200+java面试题和1000+篇技术文章：<a href="https://woaijava.cc/">博客地址</a>
 * {@code @date:} 2024-08-05 22:50
 * {@code @version:} 1.0
 */
@Slf4j
@Service
public class ChargeCouponServiceImpl implements ChargeCouponService {

    @Resource
    private ChargeCouponMapper chargeCouponMapper;
    @Resource
    private ExchangeCodeMapper exchangeCodeMapper;
    @Resource
    private RedissonClient redissonClient;

    @Override
    public CommonResult<Boolean> add(ChargeCouponAddReqDto couponAddReqDto) {
        checkCoupon(couponAddReqDto);
        ChargeCoupon record = new ChargeCoupon();
        BeanUtils.copyProperties(couponAddReqDto, record);
        record.setStatus(CouponStatusEnum.UNPUBLISHED.getStatus());
        record.setCreateTime(new Date());
        record.setCode(CouponCodeUtil.couponCode(couponAddReqDto.getCreateUserId()));
        chargeCouponMapper.insert(record);
        redissonClient.getBucket(ChargeMarketRedisKeyPrefix.CHARGE_COUPON_KEY + record.getId()).set(JSON.toJSONString(record));
        return CommonResult.success(Boolean.TRUE);
    }

    private void checkCoupon(ChargeCouponAddReqDto couponAddReqDto) {
        if (StringUtil.isBlank(couponAddReqDto.getName())) {
            throw new BusinessException("优惠券名称不能为空");
        }
        if (couponAddReqDto.getLimit() == null) {
            throw new BusinessException("领取限制不能为空");
        }
        if (couponAddReqDto.getLimit() <= 0) {
            throw new BusinessException("领取限制不正确");
        }
        if (couponAddReqDto.getCount() == null) {
            throw new BusinessException("优惠券数量不能为空");
        }
        if (couponAddReqDto.getCount() <= 0) {
            throw new BusinessException("优惠券数量不正确");
        }
        if (couponAddReqDto.getTogether() == null) {
            throw new BusinessException("叠加使用不能为空");
        }
        if (couponAddReqDto.getTogether() != 0 && couponAddReqDto.getTogether() != 1) {
            throw new BusinessException("叠加使用不正确");
        }
        if (couponAddReqDto.getUseType() == null) {
            throw new BusinessException("优惠券使用门槛类型不能为空");
        }
        // TODO: 2024-10-21 还可以进一步校验 比如满减券，满多少，减多少，折扣券，折扣率等等
        if (couponAddReqDto.getSendType() == null) {
            throw new BusinessException("优惠券发放类型不能为空");
        }
        //积分兑换，那就必须设置积分
        if (couponAddReqDto.getSendType() != CouponSendTypeEnum.POINT.getSendType() && couponAddReqDto.getPoint() == null) {
            throw new BusinessException("积分发放类型必须设置积分");
        }
    }

    @Override
    public CommonResult<Boolean> update(ChargeCouponUpdateReqDto couponUpdateReqDto) {
        ChargeCoupon record = new ChargeCoupon();
        BeanUtils.copyProperties(couponUpdateReqDto, record);
        //类型修改后，point置空
        if (couponUpdateReqDto.getSendType() != CouponSendTypeEnum.POINT.getSendType()) {
            if (couponUpdateReqDto.getPoint() != null) {
                record.setPoint(null);
            }
        }
        // TODO: 2024-10-21 其他的条件修改页可以做类似的判断，然后对数据里的属性值进行置空
        chargeCouponMapper.updateByPrimaryKey(record);
        redissonClient.getBucket(ChargeMarketRedisKeyPrefix.CHARGE_COUPON_KEY + record.getId()).set(JSON.toJSONString(record));
        return CommonResult.success(Boolean.TRUE);
    }

    @Override
    public CommonResult<Boolean> cacheStockQuantity(ChargeCouponAddReqDto couponAddReqDto) {
        // TODO: 2024-10-20 缓存库存数量
        Integer couponId = 1;
        RBucket<String> bucket = redissonClient.getBucket(ChargeMarketRedisKeyPrefix.CHARGE_COUPON_KEY + couponId);
        ChargeCoupon record = JSON.parseObject(bucket.get(), ChargeCoupon.class);
        if (record != null) {

            RBucket<String> chargeActivityBucket = redissonClient.getBucket(ChargeMarketRedisKeyPrefix.ACTIVITY_CONDITION_INFO_KEY + couponAddReqDto.getId());
            ChargeActivity chargeActivity = JSON.parseObject(chargeActivityBucket.get(), ChargeActivity.class);

            RBucket<String> chargeActivityConditionBucket = redissonClient.getBucket(ChargeMarketRedisKeyPrefix.ACTIVITY_CONDITION_KEY + chargeActivity.getActivityConditionId());
            ChargeActivityCondition chargeActivityCondition = JSON.parseObject(chargeActivityConditionBucket.get(), ChargeActivityCondition.class);

            //抢购标识
            RBucket<Integer> secondKillBucket = redissonClient.getBucket(ChargeMarketRedisKeyPrefix.CHARGE_COUPON_SECONDS_KILL_KEY + record.getId());
            secondKillBucket.set(record.getId());
            //有效期 往后延期一小时
            secondKillBucket.expire(chargeActivityCondition.getEndTime().getTime() - System.currentTimeMillis() + 3600000, TimeUnit.MILLISECONDS);

            RList<Integer> list = redissonClient.getList(ChargeMarketRedisKeyPrefix.CHARGE_COUPON_STOCK_QUANTITY_KEY + couponId);
            // 库存 缓存到redis 中
            for (int i = 0; i < record.getCount(); i++) {
                list.add(couponId);
            }
        }
        return CommonResult.success(Boolean.TRUE);
    }

    @Override
    public CommonResult<BaseRespPageDto<List<ChargeCouponRespDto>>> page(ChargeCouponPageReqDto chargeCouponPageReqDto) {
        Integer pageNum = chargeCouponPageReqDto.getPageNum();
        if (pageNum == null) {
            pageNum = 1;
        }
        Integer pageSize = chargeCouponPageReqDto.getPageSize();
        if (pageSize == null) {
            pageSize = 10;
        }
        Page<ChargeCoupon> page = PageHelper.startPage(pageNum, pageSize);
        List<ChargeCoupon> chargeCouponConditions = chargeCouponMapper.selectPageByCondition(chargeCouponPageReqDto);
        List<ChargeCouponRespDto> chargeCouponConditionRespDtoList = new ArrayList<>();
        for (ChargeCoupon chargeCoupon : chargeCouponConditions) {
            ChargeCouponRespDto chargeCouponRespDto = new ChargeCouponRespDto();
            BeanUtils.copyProperties(chargeCoupon, chargeCouponRespDto);
            chargeCouponConditionRespDtoList.add(chargeCouponRespDto);
        }
        BaseRespPageDto<List<ChargeCouponRespDto>> baseRespPageDto = new BaseRespPageDto<>();
        baseRespPageDto.setTotalCount((int) page.getTotal());
        baseRespPageDto.setTotalPage(page.getPages());
        baseRespPageDto.setData(chargeCouponConditionRespDtoList);
        return CommonResult.success(baseRespPageDto);
    }

    @Override
    public CommonResult<Boolean> delete(Integer id) {
        return chargeCouponMapper.deleteByPrimaryKey(id) > 0 ? CommonResult.success(Boolean.TRUE) : CommonResult.failed();
    }



    @Override
    public CommonResult<Boolean> start(Integer id) {
        return chargeCouponMapper.start(id) > 0 ? CommonResult.success(Boolean.TRUE) : CommonResult.failed();
    }
}